package com.swak.fx.support;

import com.swak.fx.support.ui.UI;
import com.swak.fx.support.ui.UI.Locations;
import com.swak.fx.support.ui.UI.Themes;
import com.swak.fx.support.ui.UIIcon;
import com.swak.fx.support.ui.UILifecycle;
import com.swak.fx.support.ui.UIPopup;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.stage.Window;
import javafx.util.Duration;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * Toast. 显示图标是没有问题的且设置其样式。
 * 
 * @author 618lf
 */
public class Toast extends StackPane implements UILifecycle {

	// ================================================================================
	// Properties
	// ================================================================================
	private final String STYLE_CLASS = "ui-toast";
	private final String MASK_STYLE_CLASS = "ui-toast__mask";
	private final String INNER_STYLE_CLASS = "ui-toast__inner";
	private final String ICON_STYLE_CLASS = "ui-toast__icon";
	private final String MESSAGE_STYLE_CLASS = "ui-toast__msg";
	private final String STYLESHEET = UI.load("css/UIToast.css");

	private final UIPopup popup = new UIPopup();
	private final Pane mask = new Pane();
	private final GridPane inner;
	private final UIIcon icon;
	private final Label message;
	private final Window owner;

	private final ToastConfig config;

	public Toast(Window owner, ToastConfig config) {
		this.config = config;
		this.inner = new GridPane();
		this.icon = new UIIcon(UI.Icons.SUCCESS);
		this.message = new Label(config.getMessage());
		this.owner = owner;
		this.init();
	}

	@Override
	public void initializeParts() {
		this.getStyleClass().setAll(STYLE_CLASS);
		this.getStylesheets().setAll(STYLESHEET);
		this.inner.getStyleClass().add(INNER_STYLE_CLASS);
		this.icon.getStyleClass().add(ICON_STYLE_CLASS);
		this.message.getStyleClass().add(MESSAGE_STYLE_CLASS);
		this.mask.getStyleClass().add(MASK_STYLE_CLASS);
		this.getChildren().add(this.mask);

		this.inner.getChildren().add(this.message);
		GridPane.setConstraints(this.message, 1, 0);
		GridPane.setHgrow(this.message, Priority.ALWAYS);
		GridPane.setVgrow(this.message, Priority.ALWAYS);
		GridPane.setValignment(this.message, VPos.CENTER);
		GridPane.setMargin(this.message, new Insets(0, 0, 0, 5));

		// this.inner.getChildren().add(this.icon);
		GridPane.setConstraints(this.icon, 0, 0);
		GridPane.setHgrow(this.icon, Priority.NEVER);
		GridPane.setVgrow(this.icon, Priority.ALWAYS);
		GridPane.setHalignment(this.icon, HPos.CENTER);
		GridPane.setValignment(this.icon, VPos.CENTER);
		GridPane.setMargin(this.icon, new Insets(0, 0, 0, 5));
		this.getChildren().add(this.inner);

		this.inner.setPrefHeight(40);
		this.inner.setMinWidth(220);

		double width = this.getPrefWidth();
		double height = this.getPrefHeight();
		if (width <= 0) {
			width = this.prefWidth(-1);
		}
		if (height <= 0) {
			height = this.prefHeight(-1);
		}
		this.popup.animatedProperty().set(true);
		this.popup.locationProperty().set(Locations.TOP_CENTER);
		this.popup.setOwnerWindowBlurClosed(true);
		this.popup.setOwnerWindowClickClosed(false);
		this.popup.setContentNode(this);
		this.popup.prefHeightProperty().set(height);
		this.popup.prefWidthProperty().set(width);
	}

	@Override
	public void setupValueChangedListeners() {
		UILifecycle.super.setupValueChangedListeners();
		graphicProperty().addListener((ob, o, n) -> {
			if (o != null) {
				this.inner.getChildren().remove(o);
			}
			if (n != null) {
				n.getStyleClass().add(ICON_STYLE_CLASS);
				this.inner.getChildren().add(n);
				GridPane.setConstraints(n, 0, 0);
				GridPane.setVgrow(n, Priority.ALWAYS);
				GridPane.setValignment(n, VPos.CENTER);
				GridPane.setHalignment(n, HPos.CENTER);
				GridPane.setMargin(n, new Insets(0, 10, 0, 10));
			}
		});
	}

	@Override
	public void initializeFinish() {
		if (config.getTheme() != null && config.getTheme() == Themes.Success) {
			this.success();
		} else if (config.getTheme() != null && config.getTheme() == Themes.Warning) {
			this.warning();
		} else if (config.getTheme() != null && config.getTheme() == Themes.Error) {
			this.error();
		}
	}

	// ================================================================================
	// Overridden Methods
	// ================================================================================

	@Override
	public String getUserAgentStylesheet() {
		return STYLESHEET;
	}

	/**
	 * 设置是否失去焦点就隱藏
	 * 
	 * @param boo
	 * @return
	 */
	public Toast setOwnerWindowBlurClosed(boolean boo) {
		this.popup.setOwnerWindowBlurClosed(boo);
		return this;
	}

	/**
	 * 显示
	 * 
	 * @param stage
	 * @return
	 */
	public Toast show() {
		Display.runUI(() -> {
			this.popup.show(owner, this.config.offset);
		});
		return this;
	}

	/**
	 * 隐藏
	 * 
	 * @return
	 */
	public Toast hide() {
		this.popup.hide(Duration.ZERO);
		if (config.getOnClose() != null) {
			config.getOnClose().run();
		}
		return this;
	}

	public Toast warning() {
		graphicProperty().set(new UIIcon().Icon(UI.Icons.WARNGING).fixedWidth());
		return this;
	}

	public Toast success() {
		graphicProperty().set(new UIIcon().Icon(UI.Icons.SUCCESS).fixedWidth());
		return this;
	}

	public Toast error() {
		graphicProperty().set(new UIIcon(UI.Icons.REMOVE).fixedWidth());
		return this;
	}

	// ================================================================================
	// Properties
	// ================================================================================
	private final ObjectProperty<Node> graphicProperty = new SimpleObjectProperty<Node>(this, "text-graphic");

	public ObjectProperty<Node> graphicProperty() {
		return this.graphicProperty;
	}

	/**
	 * Toast 配置
	 * 
	 * @author 618lf
	 */
	@Getter
	@Setter
	@Accessors(chain = true)
	public static class ToastConfig {

		/**
		 * 消息内容
		 */
		private String message;

		/**
		 * 主题
		 */
		private Themes theme;

		/**
		 * Ms, 设置为 0 则不自动关闭， 默认 2s 后关闭
		 */
		private Integer duration = 2000;

		/**
		 * 设置关闭后执行的函数
		 */
		private Runnable onClose;

		/**
		 * 偏移量
		 */
		private double offset = 70;

		/**
		 * 实例化配置
		 * 
		 * @return
		 */
		public static ToastConfig of() {
			return new ToastConfig();
		}
	}
}
